package rpc

import (
	"context"
	"fmt"
	s_pb "ldaccount/api/pb/server"
	"ldaccount/internal/model"

	"github.com/pkg/errors"
	"google.golang.org/grpc"

	"ldaccount/internal/service"

	"ldaccount/pkg/lueerror"
)

type ARcpHandler struct {
	*Base
	s_pb.UnimplementedLdAccountServer
}

// NewAccountRpcHandler handler init
func NewAccountRpcHandler() *ARcpHandler {
	return &ARcpHandler{
		Base:                         base,
		UnimplementedLdAccountServer: s_pb.UnimplementedLdAccountServer{},
	}
}

// RegisterHandler handler register
func (ar *ARcpHandler) RegisterHandler(server *grpc.Server) {
	s_pb.RegisterLdAccountServer(server, ar)
}

// SayHello say hello
func (ar *ARcpHandler) SayHello(ctx context.Context, in *s_pb.HelloRequest) (*s_pb.HelloReply, error) {
	ar.logger.For(ctx).Info(fmt.Sprintf("Received: %s", in.GetName()))
	if in.GetName() == "panic" {
		panic("it's panic")
	} else if in.GetName() == "lueerror" {
		return nil, lueerror.ServerError(errors.New("test lueerror"), "50000")
	} else if in.GetName() == "error" {
		return nil, errors.New("test error")
	}
	resp := &s_pb.HelloReply{Message: "Hello " + in.GetName()}
	return resp, nil
}

func (ar *ARcpHandler) originReqCheck(mobile, email, codeOrigin string) lueerror.LueError {
	if !ContainsStr([]string{"mobile", "email"}, codeOrigin) {
		return lueerror.InvalidRequest(errors.New("code_origin 错误"))
	}
	if codeOrigin == "mobile" && mobile == "" {
		return lueerror.InvalidMobile(errors.New("手机号不为空"))
	} else if codeOrigin == "email" && email == "" {
		return lueerror.InvalidMobile(errors.New("邮箱不为空"))
	}
	return nil
}

// Register 账号注册
func (ar *ARcpHandler) Register(ctx context.Context, in *s_pb.RegisterReq) (*s_pb.AccountInfoResp, error) {
	if in.GetMobile() == "" && in.GetEmail() == "" {
		return nil, lueerror.InvalidRequest(errors.New("mobile 或 email 不能都为空"))
	}
	if errL := ar.EmailMobileCheck(in.GetEmail(), in.GetMobile()); errL != nil {
		return nil, errL
	}
	if in.CodeOrigin == "" {
		in.CodeOrigin = "mobile"
	} else {
		if !ContainsStr([]string{"mobile", "email"}, in.CodeOrigin) {
			return nil, lueerror.InvalidRequest(errors.New("code_origin 错误"))
		}
	}
	if in.GetCountryCode() == "" {
		in.CountryCode = "86"
	}
	if in.Password == "" {
		in.Password = "123456"
		in.IsMD5 = false
	}
	ret, errL := service.GetAccountsSrv().RegisterAccount(ctx, in.Mobile, in.Email, in.UserName, in.Password,
		in.Code, in.CodeType, in.CountryCode, in.CodeOrigin, in.Origin, in.IsMD5)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
	}, nil
}

// Login 登陆
func (ar *ARcpHandler) Login(ctx context.Context, in *s_pb.LoginReq) (*s_pb.LoginResp, error) {
	if in.GetMobile() == "" && in.GetEmail() == "" {
		return nil, lueerror.InvalidRequest(errors.New("mobile 或 email 不能都为空"))
	}
	if in.Code == "" && in.Password == "" {
		return nil, lueerror.InvalidRequest(errors.New("请输入密码或验证码"))
	}
	if in.CodeOrigin == "" {
		in.CodeOrigin = "mobile"
	}
	if errL := ar.originReqCheck(in.Mobile, in.Email, in.CodeOrigin); errL != nil {
		return nil, errL
	}

	ret, errL := service.GetAccountsSrv().AccountLogin(ctx, in.Mobile, in.Email, in.Password, in.Code, in.CodeType,
		in.CodeOrigin, in.IsMD5)
	if errL != nil {
		return nil, errL
	}
	token, errL := ar.GenJwtToken(ret.GID, ret.Mobile, ret.Email, ret.UserName)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.LoginResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Token:    token,
	}, nil
}

// CheckMobile 检查手机号
func (ar *ARcpHandler) CheckMobile(ctx context.Context, in *s_pb.CheckMobileReq) (*s_pb.CheckMobileResp, error) {
	ret, errL := service.GetAccountsSrv().CheckMobile(ctx, in.GetMobile())
	if errL != nil {
		return nil, errL
	}
	isExist, _ := ret["is_exist"]
	if !isExist.(bool) {
		return &s_pb.CheckMobileResp{
			Mobile:  in.GetMobile(),
			IsExist: false,
		}, nil
	}
	return &s_pb.CheckMobileResp{
		Mobile:   ret["mobile"].(string),
		GId:      ret["g_id"].(string),
		UserName: ret["user_name"].(string),
		IsExist:  true,
	}, nil
}

// GetAccountByGId 根据 g_id 获取用户信息
func (ar *ARcpHandler) GetAccountByGId(ctx context.Context, in *s_pb.GetByGIdReq) (*s_pb.AccountInfoResp, error) {
	ret, errL := service.GetAccountsSrv().GetAccByGID(ctx, in.GetGId())
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Status:   ret.Status,
	}, nil
}

// GetAccountByLoginChannel 根据 email, origin 获取账号信息
func (ar *ARcpHandler) GetAccountByLoginChannel(ctx context.Context, in *s_pb.GetByLoginChannelReq) (*s_pb.AccountInfoResp, error) {
	ret, errL := service.GetAccountsSrv().GetAccountByLoginChannel(ctx, in.Email, in.Origin)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Status:   ret.Status,
	}, nil
}

// UpdateAccount 更新账户信息
func (ar *ARcpHandler) UpdateAccount(ctx context.Context, in *s_pb.UpdateAccountReq) (*s_pb.AccountInfoResp, error) {

	if errL := ar.EmailMobileCheck(in.Email, in.Mobile); errL != nil {
		return nil, errL
	}
	if in.GetCode() != "" {
		if in.GetCodeOrigin() == "" {
			in.CodeOrigin = "mobile"
		}
		if errL := ar.originReqCheck(in.Mobile, in.Email, in.CodeOrigin); errL != nil {
			return nil, errL
		}
	}
	ret, errL := service.GetAccountsSrv().UpdateAcc(ctx, in.GetGId(), in.Mobile, in.Email, in.UserName,
		in.Avatar, in.CountryCode, in.Code, in.CodeType, in.CodeOrigin)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Status:   ret.Status,
	}, nil
}

// CredibleSetMobileByGId 服务端可信设置手机号
func (ar *ARcpHandler) CredibleSetMobileByGId(ctx context.Context, in *s_pb.CredibleSetMobileReq) (*s_pb.EmptyResp, error) {
	if errL := ar.MobileCheck(in.Mobile); errL != nil {
		return nil, errL
	}
	errL := service.GetAccountsSrv().CredibleSetMobileByGId(ctx, in.GId, in.Mobile)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.EmptyResp{}, nil
}

// ResetPassword 充值密码
func (ar *ARcpHandler) ResetPassword(ctx context.Context, in *s_pb.ResetPasswordReq) (*s_pb.EmptyResp, error) {
	if in.GetCodeOrigin() == "" {
		in.CodeOrigin = "mobile"
	}
	// 根据 code 修改
	if in.Code != "" {
		if errL := ar.originReqCheck(in.Mobile, in.Email, in.CodeOrigin); errL != nil {
			return nil, errL
		}
		if errL := ar.EmailMobileCheck(in.Email, in.Mobile); errL != nil {
			return nil, errL
		}
		errL := service.GetAccountsSrv().ResetPasswordByCode(ctx, in.Mobile, in.Email, in.Password, in.Code, in.CodeType, in.CodeOrigin, in.IsMD5)
		if errL != nil {
			return nil, errL
		}
	} else {
		if in.OldPwd == "" {
			return nil, lueerror.InvalidRequest(errors.New("旧密码不为空"))
		}
		errL := service.GetAccountsSrv().ResetPasswordByOld(ctx, in.GId, in.Password, in.OldPwd, in.IsMD5)
		if errL != nil {
			return nil, errL
		}
	}
	return &s_pb.EmptyResp{}, nil
}

// SendMobileCode 发送短信验证码
func (ar *ARcpHandler) SendMobileCode(ctx context.Context, in *s_pb.SendMobileCodeReq) (*s_pb.EmptyResp, error) {
	ar.logger.For(ctx).Info("----SendMobileCode------")
	errL := service.GetAccountsSrv().SendMobileCode(ctx, in.GetMobile(), in.GetCodeType())
	if errL != nil {
		return nil, errL
	}
	return &s_pb.EmptyResp{}, nil
}

// CredibleLogin 服务端可信登陆
func (ar *ARcpHandler) CredibleLogin(ctx context.Context, in *s_pb.CredibleLoginReq) (*s_pb.LoginResp, error) {
	if in.GetEmail() == "" && in.GetMobile() == "" {
		return nil, lueerror.InvalidRequest(errors.New("email, mobile 不能都为空"))
	}
	if errL := isSupportedServer(in.GetApp()); errL != nil {
		return nil, errL
	}
	// 签名规则 mobile 值 + email 值 + app 值 + nonce 值 + secret 值 =>  sha256 签名
	signStr := fmt.Sprintf("%s%s%s%s", in.GetMobile(), in.GetEmail(), in.GetApp(), in.GetNonce())
	if errL := ar.signCheck(signStr, in.GetSign()); errL != nil {
		return nil, errL
	}
	ret, errL := service.GetAccountsSrv().GetAccByMobileEmail(ctx, in.Mobile, in.Email)
	if errL != nil {
		return nil, errL
	}
	token, errL := ar.GenJwtToken(ret.GID, ret.Mobile, ret.Email, ret.UserName)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.LoginResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Token:    token,
	}, nil
}

// CredibleBackendLogin 服务端可信登陆简易
func (ar *ARcpHandler) CredibleBackendLogin(ctx context.Context, in *s_pb.CredibleBackendLoginReq) (*s_pb.LoginResp, error) {
	if in.GetGId() == "" {
		return nil, lueerror.InvalidRequest(errors.New("g_id 不能都为空"))
	}
	if errL := isSupportedCredibleServer(in.GetApp()); errL != nil {
		return nil, errL
	}

	ret, errL := service.GetAccountsSrv().GetAccByGID(ctx, in.GId)
	if errL != nil {
		return nil, errL
	}
	token, errL := ar.GenJwtToken(ret.GID, ret.Mobile, ret.Email, ret.UserName)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.LoginResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Token:    token,
	}, nil
}

// CredibleVerifyAccountToken 服务端可信验证统一token
func (ar *ARcpHandler) CredibleVerifyAccountToken(ctx context.Context, in *s_pb.CredibleVerifyAccountTokenReq) (*s_pb.AccountTokenPayloadResp, error) {
	if errL := isSupportedCredibleServer(in.GetApp()); errL != nil {
		return nil, errL
	}
	ret, errL := ar.VerifyJwtToken(in.Token)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountTokenPayloadResp{
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		GId:      ret.GID,
		UserName: ret.UserName,
	}, nil
}

func isSupportedServer(serverName string) lueerror.LueError {
	if !ContainsStr([]string{"bgapi", "partner", "bgs", "bilin-admin"}, serverName) {
		return lueerror.InvalidRequest(errors.New("服务不支持"))
	}
	return nil
}

func isSupportedCredibleServer(serverName string) lueerror.LueError {
	if !ContainsStr([]string{"of-open"}, serverName) {
		return lueerror.InvalidRequest(errors.New("服务不支持"))
	}
	return nil
}

func (ar *ARcpHandler) signCheck(rawStr, sign string) lueerror.LueError {
	// 签名规则 string +  secret 值 =>  sha256 签名
	rawStr = fmt.Sprintf("%s%s", rawStr, ar.cfg.Keys.Secret)
	curSign, err := SignSha256(rawStr)
	if err != nil {
		return lueerror.AuthGrantErr(err)
	}
	if sign != curSign {
		return lueerror.AuthGrantErr(errors.New("签名错误"))
	}
	return nil
}

// AccountInvitation 邀请账号生成
func (ar *ARcpHandler) AccountInvitation(ctx context.Context, in *s_pb.InviteAccountReq) (*s_pb.AccountInfoResp, error) {
	if in == nil {
		return nil, nil
	}
	if errL := isSupportedServer(in.Origin); errL != nil {
		return nil, errL
	}
	// 签名规则 user_name 值 + mobile 值 + email 值 + countryCode 值 + origin 值
	signStr := fmt.Sprintf("%s%s%s%s%s", in.UserName, in.Mobile, in.Email, in.CountryCode, in.Origin)
	if errL := ar.signCheck(signStr, in.GetSign()); errL != nil {
		return nil, errL
	}
	if in.CountryCode == "" {
		in.CountryCode = "86"
	}
	ret, errL := service.GetAccountsSrv().AccountInvitation(ctx, in.Mobile, in.Email, in.UserName, in.CountryCode, in.Origin, "")
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Status:   ret.Status,
	}, nil
}

// AccountInvitationByChannel 渠道邀请账号生成
func (ar *ARcpHandler) AccountInvitationByChannel(ctx context.Context, in *s_pb.InviteAccountByChannelReq) (*s_pb.AccountInfoResp, error) {
	if in == nil {
		return nil, nil
	}
	countryCode := "86"
	ret, errL := service.GetAccountsSrv().AccountInvitation(ctx, in.Mobile, in.Email, in.UserName, countryCode, in.Origin, in.Avatar)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Status:   ret.Status,
	}, nil
}

// AccConfirmInvitation 确认邀请
func (ar *ARcpHandler) AccConfirmInvitation(ctx context.Context, in *s_pb.ConfirmInvitationReq) (*s_pb.AccountInfoResp, error) {
	if in == nil {
		return nil, nil
	}
	if in.Platform != "" && in.Platform != model.ChannelWechatMpStr {
		return nil, lueerror.InvalidChannel(fmt.Errorf("%s 暂不支持", in.Platform))
	}
	if in.CodeOrigin == "" {
		in.CodeOrigin = "mobile"
	}

	ret, errL := service.GetAccountsSrv().AccConfirmInvitation(ctx, in.GId, ar.cfg.Biz.MpAppId, in.OpenId, in.UnionId,
		in.Nickname, in.Avatar, in.Code, in.CodeType, in.CodeOrigin, model.ChannelWechatMpStr)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Status:   ret.Status,
	}, nil
}

// AccConfirmInvitation 确认邀请
func (ar *ARcpHandler) AccConfirmInvitationByChannel(ctx context.Context, in *s_pb.ConfirmInvitationByChannelReq) (*s_pb.AccountInfoResp, error) {
	if in == nil {
		return nil, nil
	}

	if in.CodeOrigin == "" {
		in.CodeOrigin = "mobile"
	}

	ret, errL := service.GetAccountsSrv().AccConfirmInvitation(ctx, in.GId, in.AppId, in.OpenId, in.UnionId,
		in.Nickname, in.Avatar, in.Code, in.CodeType, in.CodeOrigin, in.Platform)
	if errL != nil {
		return nil, errL
	}
	return &s_pb.AccountInfoResp{
		GId:      ret.GID,
		Mobile:   ret.Mobile,
		Email:    ret.Email,
		UserName: ret.UserName,
		Modified: ret.Modified,
		Status:   ret.Status,
	}, nil
}
